/*
 * @(#)XfvhdlDiscretizeUniverse.java        3.0               2004/09/14
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfvhdl;

import xfuzzy.lang.*;
import java.util.*;

/**
* Clase que discretiza el universo de discurso de una variable.
* @author Jos� Mar�a �vila Maireles, <b>e-mail</b>: josavimai@alum.us.es
* @version 3.0
*/
public class XfvhdlDiscretizeUniverse {

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  M�TO_DOS P�BLICOS DE LA CLASE				        
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   /**
   * M�todo que discretiza un universo de discurso.
   * @return Devuelve el universo de discurso de la variable v 
   * discretizado.
   */
   @SuppressWarnings({ "unchecked", "rawtypes" })
public XfvhdlUniverse discretizeUniverse(Variable v) {
      List mf_sorted = new ArrayList();
      ParamMemFunc mf1 = null;
      ParamMemFunc mf2 = null;
      double minMF1;
      double maxMF1;
      int total;
      int actual = 0;
      double valor1;
      double valor2;
      List puntos = new ArrayList();
      double factor;

      // Creo un XUniverse con cardinalidad N (que es el n�mero de bits 
      // con los que se codifican las entradas).
      XfvhdlUniverse u =
         new XfvhdlUniverse(
            v.getName(),
            v.getType().getUniverse().max(),
            v.getType().getUniverse().min(),
            XfvhdlProperties.N);

      // Creo un objeto XFvhdlInOrderParamMemFunc con las funciones 
      // miembro ordenadas de la variable v.
      XfvhdlInOrderParamMemFunc inOrderMf =
         new XfvhdlInOrderParamMemFunc(v);

      // Ordeno las funciones miembro de la variable v
      mf_sorted = inOrderMf.sort();

      // Calculo el total de funciones miembro
      total = mf_sorted.size();

      // Compruebo el solapamiento 2 a 2
      if (total >= 2) {
         // Compruebo el solapamiento de todas las funciones miembro 
         // menos las tres �ltimas
         for (int i = 0; i < total - 2; i++) {
            mf1 = (ParamMemFunc) mf_sorted.get(i);
            mf2 = (ParamMemFunc) mf_sorted.get(i + 2);
            if (inOrderMf.opMemFuncParameter(mf1, "max")
               > inOrderMf.opMemFuncParameter(mf2, "min")) {
               new XfvhdlError(4, v.getName());
            }
         }
         // Compruebo el solapamiento en las tres �ltimas funciones 
         // miembro
         mf1 = (ParamMemFunc) mf_sorted.get(total - 3);
         mf2 = (ParamMemFunc) mf_sorted.get(total - 1);

         if (inOrderMf.opMemFuncParameter(mf1, "max")
            > inOrderMf.opMemFuncParameter(mf2, "min")) {
            new XfvhdlError(4, v.getName());
         }
      }

      // Cogo las dos primeras funciones miembro
      if (total == 0) { // no puede ser que no existan funciones miembro
         new XfvhdlError(5, v.getName());
      }
      mf1 = (ParamMemFunc) mf_sorted.get(actual);
      actual++;

      if (actual == total) {
         // si solo hay una funcion miembro cogo esa funci�n miembro 2 
         // veces
         actual--;
      }
      mf2 = (ParamMemFunc) mf_sorted.get(actual);
      actual++;
      minMF1 = inOrderMf.opMemFuncParameter(mf1, "min");
      maxMF1 = inOrderMf.opMemFuncParameter(mf1, "max");

      // calculamos el factor para mantener la relaci�n entre los 
      // universos de discurso
      factor =
         (v.getType().getUniverse().max()
            - v.getType().getUniverse().min())
            / Math.pow((double) 2, (double) XfvhdlProperties.N);

      // Hago un recorrido para cada uno de los puntos del universo de 
      // discurso
      for (int i = 0;
         i < (int) Math.pow((double) 2, (double) XfvhdlProperties.N);
         i++) {
         if (i < minMF1 / factor) {
            //si el punto es menor que el m�nimo de mf1 a�ado un 0
            u.addXUniversePoint(
               new XfvhdlUniversePoint(actual - 1, 0, 0));
            puntos.add(new Double(0));
         } else if (
            i >= minMF1 / factor
               && i <= maxMF1 / factor) {
            // si i esta dentro de la funci�n miembro mf1
            valor1 = mf1.compute((double) i * factor);
            valor2 = mf2.compute((double) i * factor);
            u.addXUniversePoint(
               new XfvhdlUniversePoint(actual - 1, valor1, valor2));
         } else {
            if (total > actual) { //avanzo una funci�n miembro
               mf1 = mf2;
               mf2 = (ParamMemFunc) mf_sorted.get(actual);
               actual++;
               minMF1 = inOrderMf.opMemFuncParameter(mf1, "min");
               maxMF1 = inOrderMf.opMemFuncParameter(mf1, "max");

               valor1 = mf1.compute((double) i * factor);
               valor2 = mf2.compute((double) i * factor);
               u.addXUniversePoint(
                  new XfvhdlUniversePoint(actual - 1, valor1, valor2));
            } else { // estoy en la �ltima funci�n miembro
               valor2 = mf2.compute((double) i * factor);
               u.addXUniversePoint(
                  new XfvhdlUniversePoint(actual, valor2, 0));
            }
         }
      }

      return u;
   }

} // Fin de la clase
